package com.my.demo.shiro;

import java.util.LinkedHashMap;
import org.apache.shiro.mgt.SecurityManager;
import com.my.demo.shiro.realms.CustomerRealm;
import com.my.demo.shiro.realms.ShiroRealm;
import com.my.demo.shiro.realms.SmsRealm;
import com.my.demo.shiro.redis.RedisCacheManager;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.Filter;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SessionStorageEvaluator;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.redis.core.RedisTemplate;

/**
 * @author liangyuanshao
 * @date 2021/12/18 - 18:40
 */

@Configuration
public class ShiroConfig {


  @Bean
  public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
    return new LifecycleBeanPostProcessor();
  }

  /**
   * 为 Spring-Bean 开启对 Shiro 注解的支持
   */
  @Bean
  public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
    AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
    authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
    return authorizationAttributeSourceAdvisor;
  }

  @Bean
  @DependsOn({"getLifecycleBeanPostProcessor"})
  public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
    DefaultAdvisorAutoProxyCreator app = new DefaultAdvisorAutoProxyCreator();
    app.setProxyTargetClass(true);
    return app;
  }

  /**
   * 不向 Spring容器中注册 JwtFilter Bean，防止 Spring 将 JwtFilter 注册为全局过滤器
   * 全局过滤器会对所有请求进行拦截
   * 另一种简单做法是：直接去掉 jwtFilter()上的 @Bean 注解
   */
  @Bean
  public FilterRegistrationBean<Filter> registration(JwtFilter filter) {
    FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<Filter>(filter);
    registration.setEnabled(false);
    return registration;
  }

  @Bean
  public JwtFilter jwtFilter() {
    return new JwtFilter();
  }

  /**
   * 禁用session, 不保存用户登录状态。保证每次请求都重新认证
   */
  @Bean
  protected SessionStorageEvaluator sessionStorageEvaluator() {
    DefaultSessionStorageEvaluator sessionStorageEvaluator = new DefaultSessionStorageEvaluator();
    sessionStorageEvaluator.setSessionStorageEnabled(false);
    return sessionStorageEvaluator;
  }

  @Bean
  public ShiroFilterFactoryBean getShiroFilterFactoryBean(
      SecurityManager securityManager){

    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    //给filter设置安全管理器
    shiroFilterFactoryBean.setSecurityManager(securityManager);


    // 添加 jwt 专用过滤器
    Map<String, Filter> filterMap = new LinkedHashMap<>();
    filterMap.put("jwtFilter", jwtFilter());
    shiroFilterFactoryBean.setFilters(filterMap);

    //配置系统受限资源
    //配置系统公共资源
    Map<String,String> map = new HashMap<String,String>();
    map.put("/login","anon");//anon 设置为公共资源  放行资源放在下面
    map.put("/sendSms","anon");
    map.put("/register","anon");
    map.put("/changePassword","anon");
    map.put("/updatePassword","anon");
    map.put("/family_archives/**","anon");
    map.put("/picture/**","anon");

    map.put("/pay","anon");

    //测试
//    map.put("/uploadHead","anon");
//    map.put("/upload","anon");

    map.put("/**","jwtFilter,authc");//authc 请求这个资源需要认证和授权
//    map.put("/**","anon");
    //默认认证界面路径---当认证不通过时跳转
//    shiroFilterFactoryBean.setLoginUrl("/redirect.html");
    shiroFilterFactoryBean.setFilterChainDefinitionMap(map);

    return shiroFilterFactoryBean;
  }

  //2.创建安全管理器
  @Bean(name = "securityManager")
  public SecurityManager securityManager(RedisCacheManager redisCacheManager){
    DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
    // 2.Realm
    List<Realm> realms = new ArrayList<Realm>(4);
    realms.add(getCustomerRealm());
    realms.add(getShiroRealm());
    realms.add(getSmsRealm());
    defaultWebSecurityManager.setRealms(realms);

    // 3.关闭shiro自带的session
    DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
    subjectDAO.setSessionStorageEvaluator(sessionStorageEvaluator());
    defaultWebSecurityManager.setSubjectDAO(subjectDAO);

    defaultWebSecurityManager.setCacheManager(redisCacheManager);

    return defaultWebSecurityManager;
  }

  @Bean(name = "redisCacheManager")
  public RedisCacheManager redisCacheManager(@Qualifier("redisTemplate")RedisTemplate redisTemplate) {
    RedisCacheManager redisCacheManager = new RedisCacheManager();
    redisCacheManager.setRedisTemplate(redisTemplate);
    return redisCacheManager;
  }

  //3.创建自定义realm
  @Bean
  public Realm getSmsRealm(){
    SmsRealm smsRealm = new SmsRealm();
    return smsRealm;
  }
  @Bean
  public Realm getCustomerRealm(){
    CustomerRealm customerRealm = new CustomerRealm();
    // 设置加密算法
    CredentialsMatcher credentialsMatcher = new JwtCredentialsMatcher();
    // 设置加密次数
    customerRealm.setCredentialsMatcher(credentialsMatcher);


    //开启缓存管理器
//    customerRealm.setCachingEnabled(true);
//    customerRealm.setAuthorizationCachingEnabled(true);
//    customerRealm.setAuthorizationCachingEnabled(true);
//    customerRealm.setCacheManager(new RedisCacheManager());
//    return customerRealm;

    customerRealm.setCachingEnabled(true);//全局缓存
    customerRealm.setAuthenticationCachingEnabled(true);
    customerRealm.setAuthenticationCacheName("这是认证缓存");
    customerRealm.setAuthorizationCachingEnabled(true);
    customerRealm.setAuthorizationCacheName("这是授权缓存");
    return customerRealm;
  }


  @Bean
  public Realm getShiroRealm(){
    ShiroRealm customerRealm = new ShiroRealm();
    //设置hashed凭证匹配器
    HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
    //设置md5加密
    credentialsMatcher.setHashAlgorithmName("md5");
    //设置散列次数
    credentialsMatcher.setHashIterations(1024);
    customerRealm.setCredentialsMatcher(credentialsMatcher);
    return customerRealm;
  }





}
